package org.barad.architecture.analyzer.model.impl;

import java.lang.reflect.Field;
import java.util.List;

import kodkod.ast.Relation;
import kodkod.instance.Bounds;
import kodkod.instance.Tuple;
import kodkod.instance.TupleFactory;
import kodkod.instance.TupleSet;

public abstract class SoftwareArchitectureModelBase {
	/**
	 * Adds atoms for a relation to the atoms list
	 * @param baseName The base name from which the names of the atoms are derived
	 * @param atoms The list with all model atoms
	 * @param scope The scope for the constraint relation
	 */
	protected void addAtomsToUniverse(String baseName, List<String> atoms, int scope) {
		for(int i = 0; i < scope; i++) {
			atoms.add(baseName + i);
		}
	}
	
	/**
	 * Add range of tuples for a unary relation to the bounds of the model
	 * @param bounds The bounds instance
	 * @param factory The tuple factory instance
	 * @param begIndex The beginning index of the atom
	 * @param endIndex The end index of the atom
	 */
	protected void boundRangefOfUnaryRelation(Relation relation, Bounds bounds, TupleFactory factory, int begIndex, int endIndex) {
		String baseName = relation.toString();
		Tuple fromTuple = factory.tuple(baseName + begIndex);
		Tuple toTuple = factory.tuple(baseName + endIndex);
		TupleSet tupleSet = factory.range(fromTuple, toTuple);
		setFieldValue(baseName.toLowerCase() + "Set", tupleSet);
		bounds.bound(relation, tupleSet);
	}
	
	/**
	 * Add range of tuples for a binary relation to the bounds of the model
	 * @param bounds The bounds instance
	 * @param factory The tuple factory instance
	 * @param begIndex The beginning index of the atom
	 * @param endIndex The end index of the atom
	 */
	protected void boundRangeOfBinaryRelation(Relation relation, TupleSet toTupleSet, Bounds bounds, TupleFactory factory, int begIndex, int endIndex) {
		String baseName = relation.toString();
		Tuple fromTuple = factory.tuple(baseName + begIndex);
		Tuple toTuple = factory.tuple(baseName + endIndex);
		TupleSet tupleSet = factory.range(fromTuple, toTuple);
		setFieldValue(baseName.toLowerCase() + "Set", tupleSet);
		bounds.bound(relation, tupleSet.product(toTupleSet));
	}
	
	/**
	 * Set a field given its name to a tuple set using reflection
	 * @param fieldName The name of the field
	 * @param tupleSet The tuple set
	 */
	protected void setFieldValue(String fieldName, TupleSet tupleSet) {
		Field field = null;
		try {
			field = getClass().getDeclaredField(fieldName);
		} catch (NoSuchFieldException nsfe) {
			System.out.println(nsfe);
		}
		field.setAccessible(true);
		try {
			field.set(this, tupleSet);
		} catch (IllegalAccessException iae) {
			/*ignore*/
		}
	}
}
